"The web framework for perfectionists with deadlines"
— Django Software Foundation
Aber was bedeutet das eigentlich?
Stellen Sie sich vor, Sie wollen ein Haus bauen. Sie könnten:
Django ist wie ein Fertighaus-System für Websites!
Speichern und Abrufen von Daten (Benutzer, Artikel, Bestellungen...)
Login, Registrierung, Passwort-Reset - alles fertig!
HTML-Seiten mit dynamischen Inhalten füllen
Schutz vor Hackerangriffen ist eingebaut
# Sie müssen ALLES selbst schreiben:
1. Wie speichere ich Benutzerdaten?
2. Wie prüfe ich, ob ein Passwort sicher ist?
3. Wie verhindere ich SQL-Injection-Angriffe?
4. Wie zeige ich eine HTML-Seite an?
5. Wie verbinde ich mich mit der Datenbank?
6. Wie handle ich Sessions?
7. ...und 1000 andere Dinge
→ Monate an Arbeit! 😰
# Django gibt Ihnen fertige Lösungen:
from django.contrib.auth.models import User # Benutzer-System: ✅
from django.db import models # Datenbank: ✅
from django.shortcuts import render # HTML anzeigen: ✅
# Sie können sich auf Ihre Idee konzentrieren!
# Django kümmert sich um den Rest.
→ Tage statt Monate! 🚀
DRY - Don't Repeat Yourself
Warum das Rad neu erfinden? Django hat die häufigsten Probleme bereits gelöst!
Wo? Lawrence Journal-World (Zeitung in Kansas, USA)
Problem: Journalisten brauchten schnell neue Web-Features
Lösung: Adrian Holovaty & Simon Willison entwickelten ein Framework
→ Musste schnell sein, robust sein, leicht bedienbar sein
Django wurde der Öffentlichkeit zur Verfügung gestellt
Namensgebung: Nach Django Reinhardt (Jazz-Gitarrist)
Erste stabile Version
Django Software Foundation gegründet
Über 20 Jahre Entwicklung
Millionen von Websites weltweit
Aktive Community von tausenden Entwicklern
Websites mit Artikeln, News, Blogs
🌟 Bekanntes Beispiel: The Washington Post nutzt Django
Online-Shops mit Produkten, Warenkorb, Bezahlung
📦 Frameworks wie Django Oscar bieten fertige Shop-Lösungen
Plattformen wie Facebook, Instagram
🌟 Bekanntes Beispiel: Instagram wurde ursprünglich mit Django gebaut!
Online-Kurse, E-Learning-Plattformen
🎯 Viele Online-Akademien nutzen Django
Interne Tools, CRM, Projektmanagement
💼 Viele Startups nutzen Django für MVP (Minimum Viable Product)
Backend für Mobile Apps, SPAs, IoT
🚀 Unser Kurs-Fokus! Von Django zu REST APIs
Die größte Django-Installation der Welt!
"Django ermöglicht uns, schnell zu experimentieren und zu wachsen"
Musik-Streaming für Millionen
Traditionelle Zeitung goes Digital
Visuelles Discovery-Tool
Kommentar-System für Millionen Websites
Video-Plattform (ursprünglich)
Wenn Django gut genug für Instagram und Spotify ist, ist es gut genug für Ihr Projekt! Sie lernen eine Technologie, die in der echten Welt eingesetzt wird.
Django organisiert Code in drei klare Bereiche
┌─────────────────────────────────────────────────────────┐
│ Restaurant │
├─────────────────────────────────────────────────────────┤
│ │
│ 👨🍳 Koch (View) 📋 Rezept (Template) │
│ Bereitet Essen zu Wie das Essen │
│ nach Rezept präsentiert wird │
│ │
│ ↕ ↕ │
│ │
│ 🥘 Zutaten (Model) │
│ Alle Lebensmittel │
│ im Kühlschrank │
│ │
└─────────────────────────────────────────────────────────┘
Was wird gespeichert?
class Movie(models.Model):
title = models.CharField(max_length=200)
year = models.IntegerField()
genre = models.CharField(max_length=100)
rating = models.DecimalField()
# → Wird zu Datenbank-Tabelle "movies"
Wie sieht es aus?
<h1>Alle Filme</h1>
<ul>
{% for movie in movies %}
<li>{{ movie.title }} ({{ movie.year }})</li>
{% endfor %}
</ul>
# {{ }} → Variable einfügen
# {% %} → Logik (for, if, ...)
Was passiert?
def movie_list(request):
# 1. Daten aus DB holen
movies = Movie.objects.all()
# 2. An Template übergeben
return render(request, 'movies.html', {
'movies': movies
})
# → Browser zeigt gefülltes HTML an
┌─────────────┐
│ Browser │ "Ich will alle Filme sehen!"
│ (Client) │ → GET http://example.com/movies/
└─────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Django Server │
├─────────────────────────────────────────────────────────┤
│ │
│ 1️⃣ URLs (Router)
│ urlpatterns = [ │
│ "Welche View ist für /movies/ zuständig?" │
│ → movie_list View │
│ │
│ ▼ │
│ │
│ 2️⃣ View (Logik)
│ def movie_list(request): │
│ movies = Movie.objects.all() ← 3️⃣ Model (DB)
│ return render(..., movies) │
│ │ │
│ ▼ │
│ │
│ 4️⃣ Template (HTML)
│ {% for movie in movies %} │
│ {{ movie.title }} │
│ {% endfor %} │
│ │
└─────────────────────────────────────────────────────────┘
│
▼ Fertiges HTML
┌─────────────┐
│ Browser │ Zeigt Liste der Filme
└─────────────┘
Browser fragt: /movies/
Django schaut in urls.py: Welche View passt?
urlpatterns = [
path('movies/', movie_list), # ← Diese View!
]
Die movie_list View wird aufgerufen
def movie_list(request):
# request = alle Infos vom Browser
# (welche URL, welcher User, ...)
View fragt Model: "Gib mir alle Filme!"
movies = Movie.objects.all()
# Django übersetzt das zu SQL:
# SELECT * FROM movies;
View gibt Daten an Template
return render(request, 'movies.html', {
'movies': movies # ← Daten fürs Template
})
Template wird mit Daten gefüllt → fertiges HTML
Django sendet HTML zurück zum Browser
Django generiert komplette HTML-Seiten auf dem Server
User klickt Link → Django generiert HTML → Browser zeigt Seite
Beispiel: Blog-Website
1. User besucht: www.meinblog.de/artikel/
2. Django:
- Holt alle Artikel aus der Datenbank
- Steckt sie in ein HTML-Template
- Sendet fertiges HTML zurück
3. Browser zeigt die Seite
Bei jedem Link-Klick → neues HTML vom Server!
Django wird zum reinen Daten-Lieferanten
Stellen Sie sich einen Restaurant-Service vor:
┌──────────────┐ ┌──────────────┐
│ Frontend │ ← JSON-Daten → │ Django │
│ (React/Vue) │ über HTTP │ REST API │
│ │ │ (Backend) │
└──────────────┘ └──────────────┘
│ │
│ 1. GET /api/movies/ │
│ ─────────────────────────────────→ │
│ │ Holt Daten
│ │ aus DB
│ │
│ 2. Response: JSON │
│ ←───────────────────────────────── │
│ [ │
│ {"title": "Matrix", ...} │
│ ] │
│ │
│ 3. Frontend baut HTML │
│ Matrix │
│ │
└──────────────┘ └──────────────┘
Smartphone-App (iOS/Android)
│
│ GET /api/movies/
▼
Django REST API
│
│ [{"title": "Matrix"}, ...]
▼
App zeigt Liste
# Eine API für alle Plattformen!
React im Browser
│
│ fetch('/api/movies/')
▼
Django REST API
│
│ [{"title": "Matrix"}, ...]
▼
React baut HTML
# Smooth, schnell, App-Feeling!
# views.py
def movie_list(request):
movies = Movie.objects.all()
return render(request, 'movies.html', {
'movies': movies
})
# Response: Komplettes HTML
<!DOCTYPE html>
<html>
<body>
<h1>Filme</h1>
<ul>
<li>Matrix</li>
<li>Inception</li>
</ul>
</body>
</html>
# Browser zeigt direkt die Seite
# Jeder Klick → neue HTML-Seite
# views.py
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
# Response: Nur JSON-Daten
[
{
"id": 1,
"title": "Matrix",
"year": 1999,
"genre": "Sci-Fi"
},
{
"id": 2,
"title": "Inception",
"year": 2010,
"genre": "Sci-Fi"
}
]
# Frontend (React/Vue/App) baut HTML
# Keine Seiten-Reloads, smooth!
┌────────────────────┬─────────────────────┬────────────────────────┐
│ Kriterium │ Traditionell │ REST API │
├────────────────────┼─────────────────────┼────────────────────────┤
│ Output │ HTML │ JSON/XML │
│ Frontend │ Django Templates │ React/Vue/Angular/App │
│ Seitenreload │ Bei jedem Klick │ Keine (SPA) │
│ Use Case │ Websites │ Apps, SPAs, IoT │
│ Entwicklung │ Alles in Django │ Frontend getrennt │
│ Mobile-fähig │ ⚠️ Nicht optimal │ ✅ Perfekt │
│ SEO │ ✅ Sehr gut │ ⚠️ Braucht SSR │
│ Komplexität │ ✅ Einfacher │ ⚠️ Zwei Projekte │
│ Flexibilität │ ⚠️ Eingeschränkt │ ✅ Sehr flexibel │
│ Performance │ ⚠️ Jede Seite neu │ ✅ Nur Daten laden │
└────────────────────┴─────────────────────┴────────────────────────┘
Ein Toolkit, das aus Django einen API-Superhelden macht!
# Django kann auch APIs ohne DRF, aber...
from django.http import JsonResponse
from .models import Movie
def movie_list(request):
# 1. Daten aus DB holen
movies = Movie.objects.all()
# 2. Manuell zu JSON konvertieren
data = []
for movie in movies:
data.append({
'id': movie.id,
'title': movie.title,
'year': movie.year,
# ... jedes Feld manuell!
})
# 3. Als JSON zurückgeben
return JsonResponse(data, safe=False)
# ❌ Viel Arbeit!
# ❌ Keine Validierung
# ❌ Keine Authentication
# ❌ Keine Dokumentation
# ❌ Kein Standard
from rest_framework import viewsets
from .models import Movie
from .serializers import MovieSerializer
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
# Das war's! DRF macht automatisch:
# ✅ JSON-Konvertierung
# ✅ Validierung
# ✅ CRUD-Operationen (Create, Read, Update, Delete)
# ✅ Authentication
# ✅ Permissions
# ✅ Pagination
# ✅ Filtering
# ✅ Dokumentation
# ✅ Browsable API (Web-UI zum Testen!)
# Von 30 Zeilen auf 3 Zeilen! 🚀
Python ↔ JSON automatisch
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = '__all__'
# Macht automatisch:
# Python Object → JSON (für Response)
# JSON → Python Object (von Request)
# + Validierung inklusive!
Sie definieren einmal die Struktur, DRF macht den Rest!
Alle Operationen automatisch
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
# Generiert automatisch:
# GET /movies/ → Liste aller Filme
# POST /movies/ → Neuen Film erstellen
# GET /movies/1/ → Film #1 Details
# PUT /movies/1/ → Film #1 bearbeiten
# DELETE /movies/1/ → Film #1 löschen
# Alles ohne extra Code!
Kein URL-Mapping nötig
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('movies', MovieViewSet)
# Generiert automatisch alle URLs:
# /movies/
# /movies/{id}/
# + Namen für reverse()
# Eine Zeile → komplettes Routing!
Token, JWT, Session - fertig!
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}
# Token-Auth aktiviert!
# User bekommt Token bei Login
# Token in Header → User authentifiziert
# Alles automatisch!
Zugriffskontrolle leicht gemacht
from rest_framework.permissions import IsAuthenticated
class MovieViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]
# Nur angemeldete User dürfen zugreifen!
# Viele vordefinierte Permissions:
# - AllowAny
# - IsAuthenticated
# - IsAdminUser
# - IsAuthenticatedOrReadOnly
# + eigene Permissions möglich!
API im Browser testen!
# Automatisch dabei:
# Schöne Web-UI zum Testen
# Im Browser: http://localhost:8000/api/movies/
# Features:
# - API durchsuchen
# - POST-Requests abschicken
# - JSON formatiert anzeigen
# - Formulare für Daten-Eingabe
# - Login-Funktion
# Perfekt für Entwicklung!
Beispiel: Movie-API für eine Film-App
# models.py
class Movie(models.Model):
title = models.CharField(max_length=200)
year = models.IntegerField()
genre = models.CharField(max_length=100)
rating = models.DecimalField(max_digits=3, decimal_places=1)
def __str__(self):
return f"{self.title} ({self.year})"
# python manage.py makemigrations
# python manage.py migrate
# → Datenbank-Tabelle erstellt!
# serializers.py
from rest_framework import serializers
from .models import Movie
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = ['id', 'title', 'year', 'genre', 'rating']
# Kann jetzt Python ↔ JSON übersetzen
# + Validiert automatisch!
# views.py
from rest_framework import viewsets
from .models import Movie
from .serializers import MovieSerializer
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
# Fertig! Alle CRUD-Operationen funktionieren!
# urls.py
from rest_framework.routers import DefaultRouter
from .views import MovieViewSet
router = DefaultRouter()
router.register('movies', MovieViewSet)
urlpatterns = router.urls
# URLs automatisch generiert!
# Server starten
python manage.py runserver
# API-Endpoints verfügbar:
GET http://localhost:8000/api/movies/
POST http://localhost:8000/api/movies/
GET http://localhost:8000/api/movies/1/
PUT http://localhost:8000/api/movies/1/
PATCH http://localhost:8000/api/movies/1/
DELETE http://localhost:8000/api/movies/1/
# Im Browser: Browsable API!
# Mit Postman: JSON-Requests!
# Von React App: fetch() Calls!
🎉 Produktionsreife API in 20 Zeilen Code!
Traditionelle Server-Rendered Websites
✅ Vorteil: Schnell entwickelt, SEO perfekt, alles in einem
⚠️ Nachteil: Kein "App-Feeling", bei jedem Klick Reload
Moderne API-First Projekte
✅ Vorteil: Flexibel, modern, App-Feeling, wiederverwendbar
⚠️ Nachteil: Mehr Komplexität (Frontend + Backend getrennt)
Hybrid-Ansatz:
myproject/
├── api/ # DRF für Mobile App
│ └── views.py # → JSON API
│
└── web/ # Django Templates für Website
└── views.py # → HTML Seiten
# Beispiel: Netflix
# - Website: Django Templates
# - Mobile App: DRF API
# - Smart TV: DRF API
# Beste aus beiden Welten!
Alles dabei, was Sie brauchen
→ Sie bauen Features, nicht Infrastruktur!
Von Idee zu Produkt in Rekordzeit
Perfekt für Startups und tight Deadlines!
Sicherheit eingebaut
Sie müssen nicht Sicherheits-Experte sein!
Von 10 zu 10 Millionen Usern
Wächst mit Ihrem Projekt mit!
Beste Docs im Web-Framework-Bereich
docs.djangoproject.com → Ihre Bibel!
Hilfe überall
Problem? Google findet 99% der Lösungen!
Verstehen Sie die Denkweise hinter Django
"Schreibe keinen Code zweimal"
# ❌ Schlecht: Code wiederholt
def get_movies_for_web():
return Movie.objects.filter(is_active=True)
def get_movies_for_api():
return Movie.objects.filter(is_active=True)
# ✅ Gut: Einmal definieren
class Movie(models.Model):
# ...
@classmethod
def get_active(cls):
return cls.objects.filter(is_active=True)
# Überall nutzen:
Movie.get_active() # In Web-Views
Movie.get_active() # In API-Views
Django hilft, Code-Duplikation zu vermeiden. Ein Konzept, eine Implementierung!
"Komponenten sind unabhängig"
# Model weiß nichts von View
class Movie(models.Model):
title = models.CharField(max_length=200)
# View weiß nichts von Template
def movie_list(request):
movies = Movie.objects.all()
return render(request, 'movies.html', {'movies': movies})
# Template weiß nichts von Datenbank
{% for movie in movies %}
{{ movie.title }}
{% endfor %}
# Jede Schicht ist austauschbar!
# Model ändern → View funktioniert weiter
# Template ändern → Model bleibt gleich
Sie können jede Komponente ändern, ohne andere zu brechen. Flexibilität pur!
"Code soll klar sein, keine Magie"
# Django macht Dinge explizit sichtbar
# ✅ Sie sehen, was passiert:
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all() # ← Welche Daten?
serializer_class = MovieSerializer # ← Wie serialisiert?
permission_classes = [IsAuthenticated] # ← Wer darf zugreifen?
# Keine versteckte Magie!
# Alles ist im Code sichtbar und nachvollziehbar
# ❌ Andere Frameworks verstecken Logik:
# @MagicDecorator # ← Was macht das genau?
# def view():
# pass # ← Woher kommen die Daten?
Kein "Magic" - Sie verstehen immer, was Ihr Code macht!
"Sinnvolle Defaults, aber anpassbar"
# Django hat kluge Standard-Einstellungen
# Standard-Struktur (funktioniert sofort):
myapp/
models.py # ← Django weiß: Hier sind Models
views.py # ← Django weiß: Hier sind Views
urls.py # ← Django weiß: Hier sind URLs
templates/ # ← Django weiß: Hier ist HTML
# Aber alles anpassbar!
# settings.py:
TEMPLATES = [{
'DIRS': ['/my/custom/path/'], # ← Eigener Pfad
}]
# Beste aus beiden Welten:
# - Anfänger: Nutzen Conventions (schnell loslegen)
# - Profis: Konfigurieren alles nach Bedarf
Sie müssen nicht alles konfigurieren - Django hat sinnvolle Defaults. Aber wenn nötig, ist alles anpassbar!
"Von Idee zu Produkt in Rekordzeit"
# Django ist für schnelle Entwicklung gebaut
# Tag 1: Model erstellen
class Movie(models.Model):
title = models.CharField(max_length=200)
# Tag 2: Admin-Panel (automatisch!)
from django.contrib import admin
admin.site.register(Movie)
# → Fertige Admin-Oberfläche!
# Tag 3: API (mit DRF)
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
# → Fertige REST API!
# Tag 4-5: Frontend, Tests, Deploy
# → MVP fertig! 🎉
# Andere Frameworks: Wochen für gleiches Ergebnis
"The web framework for perfectionists with deadlines" - Das ist nicht nur Marketing!
"Sicherheit ist eingebaut, nicht optional"
# Django macht Sicherheit automatisch
# CSRF-Protection (Cross-Site Request Forgery):
# Jedes Form hat automatisch CSRF-Token
{% csrf_token %} # ← Django fügt Token ein
# XSS-Protection (Cross-Site Scripting):
{{ user_input }} # ← Automatisch escaped!
# <script>alert('hack123')</script> wird zu:
# <script>alert('hack')</script>
# SQL-Injection unmöglich:
Movie.objects.filter(title=user_input)
# ← ORM escapet automatisch, keine manuelle SQL!
# Clickjacking-Protection:
# X-Frame-Options Header automatisch gesetzt
# Sie müssen nichts tun - Django schützt Sie!
Sicherheit ist kein Add-On, sondern Teil des Kerns!
Tausende von Packages erweitern Django's Funktionalität
REST APIs bauen (unser Kurs-Fokus!)
pip install djangorestframework
# In 5 Minuten eine API:
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
Social Login (Google, Facebook, GitHub...)
pip install django-allauth
# Features:
# - Login mit Google
# - Login mit Facebook
# - Login mit GitHub
# - Email-Bestätigung
# - Passwort-Reset
Schöne Forms ohne viel HTML
pip install django-crispy-forms
# Forms werden automatisch schön:
{% load crispy_forms_tags %}
{{ form|crispy }}
# → Bootstrap-styled Form!
Performance-Analyse während Entwicklung
pip install django-debug-toolbar
# Zeigt im Browser:
# - Anzahl SQL-Queries
# - Langsame Queries
# - Template-Rendering-Zeit
# - Cache-Statistiken
# → N+1 Query Problems finden!
Zahlungen akzeptieren
pip install dj-stripe
# Stripe-Zahlungen in Django:
# - Kreditkarten
# - Subscriptions
# - Webhooks
# - Invoices
Background Tasks & Async Jobs
pip install celery
# Hintergrund-Tasks:
@task
def send_newsletter(user_ids):
# Läuft im Hintergrund
for user_id in user_ids:
send_email(user_id)
# User wartet nicht!
Such- und Filterfunktionen
pip install django-filter
# Automatisches Filtering:
class MovieFilter(django_filters.FilterSet):
class Meta:
model = Movie
fields = ['genre', 'year']
# /api/movies/?genre=Sci-Fi&year=1999
# → Automatisch gefiltert!
Content Management System
pip install django-cms
# Komplettes CMS:
# - Drag & Drop Editor
# - Page-Management
# - Plugin-System
# - Multi-Language
# → WordPress-Alternative!
Jedes Framework hat seine Stärken - Hier ist Django's Platz
┌─────────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
│ Kriterium │ Django │ Flask │ FastAPI │ Pyramid │
├─────────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
│ Typ │ Full-Stack │ Micro │ Micro │ Full-Stack │
│ Batteries │ ✅ Viele │ ⚠️ Wenige │ ⚠️ Wenige │ ✅ Viele │
│ Admin Panel │ ✅ Ja │ ❌ Nein │ ❌ Nein │ ❌ Nein │
│ ORM │ ✅ Django ORM│ ⚠️ Optional │ ⚠️ Optional │ ⚠️ Optional │
│ Learning Curve │ ⚠️ Mittel │ ✅ Einfach │ ✅ Einfach │ ⚠️ Schwer │
│ Performance │ ✅ Gut │ ✅ Gut │ ⭐ Sehr gut │ ✅ Gut │
│ API Support │ ✅ DRF │ ✅ Flask-REST│ ⭐ Native │ ✅ Cornice │
│ Async Support │ ✅ Ab v3.1 │ ✅ Ja │ ⭐ Native │ ✅ Ja │
│ Use Case │ Große Apps │ Kleine Apps │ APIs │ Enterprise │
│ Community │ ⭐ Sehr groß │ ✅ Groß │ ✅ Wachsend │ ⚠️ Klein │
│ Job Market │ ⭐ Sehr viel │ ✅ Viel │ ✅ Wachsend │ ⚠️ Wenig │
└─────────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
"Batteries Included" Full-Stack
# Eine App in 10 Minuten:
# - Models definieren
# - Admin Panel ✅
# - User Management ✅
# - Forms ✅
# - Security ✅
# → Sofort produktiv!
"Micro" Framework - Du entscheidest
# Minimale App:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello!'
# Aber: Admin? ORM? Auth?
# → Musst du selbst bauen!
Modern, schnell, API-fokussiert
from fastapi import FastAPI
app = FastAPI()
@app.get("/movies/")
async def get_movies():
return movies
# Automatische OpenAPI Docs!
# Sehr schnell!
# Aber: Keine Website-Features
Django ist die Basis, DRF erweitert für APIs
┌─────────────────────────────────────────────────────────────┐
│ Django (Core) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 🗄️ Models (Datenbank-Struktur) │
│ 🔐 Authentication (User-System) │
│ 🛡️ Security (CSRF, XSS, SQL-Injection) │
│ 📝 Forms & Validation │
│ 🔗 URL Routing │
│ ⚙️ Settings & Configuration │
│ 🗃️ Migrations │
│ 👨💼 Admin Panel │
│ │
└─────────────────────────────────────────────────────────────┘
↓
Nutzt Django's Features
↓
┌─────────────────────────────────────────────────────────────┐
│ Django REST Framework (DRF) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 🔄 Serializers (Python ↔ JSON) │
│ 🎯 ViewSets (CRUD-Logic) │
│ 🔗 Routers (Auto URL-Generation) │
│ 🔐 Token/JWT Authentication │
│ 🛡️ API Permissions │
│ 📄 Pagination │
│ 🔍 Filtering & Search │
│ 🌐 Browsable API │
│ 📚 OpenAPI/Swagger Docs │
│ │
└─────────────────────────────────────────────────────────────┘
# models.py - Django Core
class Movie(models.Model):
title = models.CharField(max_length=200)
year = models.IntegerField()
genre = models.CharField(max_length=100)
class Meta:
db_table = 'movies'
ordering = ['-year']
# Django kümmert sich um:
# - Datenbank-Tabelle erstellen
# - SQL-Queries generieren
# - Validation
# - Migrations
# serializers.py - DRF
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie # ← Nutzt Django Model!
fields = '__all__'
# DRF macht:
# - Python Object → JSON
# - JSON → Python Object
# - Validierung für API-Requests
# views.py - DRF
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all() # ← Django ORM!
serializer_class = MovieSerializer
permission_classes = [IsAuthenticated] # ← Django Auth!
# DRF baut auf Django auf:
# - Nutzt Django's Models
# - Nutzt Django's Authentication
# - Nutzt Django's Permissions
# - Nutzt Django's URL-System
pip install django djangorestframeworkEin konkretes Beispiel zum Verstehen
# models.py (gleich für beide!)
class BlogPost(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, on_delete=CASCADE)
published_at = models.DateTimeField(auto_now_add=True)
# views.py - Django Template View
def blog_list(request):
posts = BlogPost.objects.all()
return render(request, 'blog/list.html', {
'posts': posts
})
# templates/blog/list.html
<!DOCTYPE html>
<html>
<head><title>Mein Blog</title></head>
<body>
<h1>Alle Blog-Posts</h1>
{% for post in posts %}
<article>
<h2>{{ post.title }}</h2>
<p>{{ post.content }}</p>
<small>Von {{ post.author }} am {{ post.published_at }}</small>
</article>
{% endfor %}
</body>
</html>
# User-Erlebnis:
# - Besucht: www.meinblog.de/posts/
# - Sieht: Komplette HTML-Seite
# - Klick auf Post → Neue Seite lädt
# - Klassische Website
# models.py (gleich wie oben!)
# Gleiche BlogPost Model
# serializers.py - DRF
class BlogPostSerializer(serializers.ModelSerializer):
author_name = serializers.CharField(source='author.username', read_only=True)
class Meta:
model = BlogPost
fields = ['id', 'title', 'content', 'author_name', 'published_at']
# views.py - DRF ViewSet
class BlogPostViewSet(viewsets.ModelViewSet):
queryset = BlogPost.objects.all()
serializer_class = BlogPostSerializer
# urls.py
router = DefaultRouter()
router.register('posts', BlogPostViewSet)
# Response (JSON):
GET /api/posts/
[
{
"id": 1,
"title": "Mein erster Post",
"content": "Das ist der Inhalt...",
"author_name": "Max",
"published_at": "2025-11-09T10:30:00Z"
},
{
"id": 2,
"title": "Zweiter Post",
"content": "Mehr Inhalt...",
"author_name": "Anna",
"published_at": "2025-11-10T14:20:00Z"
}
]
# User-Erlebnis:
# - React App ruft API auf
# - Baut HTML dynamisch
# - Smooth Scrolling, keine Reloads
# - App-Feeling!
┌─────────────────────────┬──────────────────────┬──────────────────────┐
│ Frage │ Django (Traditional) │ DRF (API) │
├─────────────────────────┼──────────────────────┼──────────────────────┤
│ Nur Website? │ ✅ Perfekt │ ⚠️ Overkill │
│ Auch Mobile App geplant?│ ❌ Schwierig │ ✅ Perfekt │
│ SEO wichtig? │ ✅ Sehr gut │ ⚠️ SSR nötig │
│ Modernes UI (React/Vue)?│ ⚠️ Kompliziert │ ✅ Ideal │
│ Schnelle Entwicklung? │ ✅ Sehr schnell │ ⚠️ Frontend extra │
│ Mehrere Clients? │ ❌ Schwierig │ ✅ Eine API für alle │
│ Interaktivität? │ ⚠️ Page Reloads │ ✅ Smooth │
└─────────────────────────┴──────────────────────┴──────────────────────┘
Hybrid-Lösung (Beste aus beiden Welten):
myproject/
├── blog/ # Django App für Website
│ ├── views.py # → render() für HTML
│ ├── templates/ # → HTML Templates
│ └── urls.py # → /blog/, /blog/post/1/
│
└── api/ # DRF App für Mobile
├── serializers.py # → JSON Responses
├── views.py # → ViewSets
└── urls.py # → /api/posts/
# Beispiel: Medium.com
# - Website: Server-rendered für SEO
# - Mobile App: REST API
# - Admin: Django Admin Panel
# Sie müssen sich nicht entscheiden - nutzen Sie beides!
Schritt für Schritt zum API-Profi
Models verstehen
→ Die Basis für alles weitere!
Daten verwalten
→ Sehen wie Django mit Daten umgeht
Was ist eine API?
→ Theorie bevor wir loslegen
DRF Setup
→ Django wird zur API-Maschine!
Daten-Konvertierung
→ Das Herzstück von DRF!
API-Logik
→ Von einfach zu elegant!
Endpoints definieren
→ API-Struktur festlegen
Zugriff schützen
→ Nur für angemeldete User!
API optimieren
→ Production-ready machen!
Live gehen
→ Fertig für Production!
Verstehen Sie die Organisation
firstmovieapi/ # 🏠 Projekt-Root
│
├── venv/ # 🔒 Virtuelle Umgebung
│ └── ... # Python Packages isoliert
│
├── firstmovieapi/ # ⚙️ Projekt-Konfiguration
│ ├── __init__.py
│ ├── settings.py # ⚙️ Alle Einstellungen
│ │ # - INSTALLED_APPS (Django + DRF)
│ │ # - REST_FRAMEWORK Settings
│ │ # - Database Config
│ │ # - Authentication
│ │
│ ├── urls.py # 🔗 Haupt-URL-Routing
│ │ # /admin/ → Django Admin
│ │ # /api/ → DRF API
│ │
│ ├── wsgi.py # 🌐 Deployment (Apache/Nginx)
│ └── asgi.py # ⚡ Async Support
│
├── movies/ # 🎬 App: Movies
│ ├── migrations/ # 🗃️ Datenbank-Änderungen
│ │ ├── 0001_initial.py
│ │ └── ...
│ │
│ ├── __init__.py
│ ├── models.py # 🗄️ Django Models
│ │ # class Movie(models.Model)
│ │ # class Artist(models.Model)
│ │ # class MovieCasting(models.Model)
│ │
│ ├── serializers.py # 🔄 DRF Serializers
│ │ # class MovieSerializer(...)
│ │ # class ArtistSerializer(...)
│ │
│ ├── views.py # 🎯 DRF ViewSets
│ │ # class MovieViewSet(...)
│ │ # class ArtistViewSet(...)
│ │
│ ├── urls.py # 🔗 App-URLs
│ │ # Router für ViewSets
│ │
│ ├── admin.py # 👨💼 Django Admin Config
│ │ # admin.site.register(Movie)
│ │
│ ├── tests.py # ✅ Unit Tests
│ │ # class MovieAPITestCase(...)
│ │
│ └── apps.py # 📦 App-Konfiguration
│
├── static/ # 🎨 CSS, JS, Images
│ └── ... # (Optional, für Admin/Browsable API)
│
├── media/ # 📁 User Uploads
│ └── ... # (Film-Poster, etc.)
│
├── manage.py # 🔧 Django Management-Tool
│ # python manage.py runserver
│ # python manage.py migrate
│ # python manage.py createsuperuser
│
├── requirements.txt # 📦 Dependencies
│ # Django==5.1.3
│ # djangorestframework==3.14.0
│ # ...
│
├── .env # 🔐 Secrets (nicht in Git!)
│ # SECRET_KEY=...
│ # DATABASE_URL=...
│
├── .gitignore # 🙈 Was Git ignorieren soll
│ # venv/
│ # *.pyc
│ # db.sqlite3
│
└── README.md # 📖 Projekt-Dokumentation
# Zentrale Konfiguration:
INSTALLED_APPS = [
'django.contrib.admin',
'rest_framework', # DRF
'movies', # Unsere App
]
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
# Datenbank-Struktur:
class Movie(models.Model):
title = models.CharField(max_length=200)
year = models.IntegerField()
# Django macht daraus Tabelle:
# CREATE TABLE movies_movie (
# id INTEGER PRIMARY KEY,
# title VARCHAR(200),
# year INTEGER
# );
# Python ↔ JSON:
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = '__all__'
# Movie Object → JSON
# JSON → Movie Object
# API-Logik:
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
# Alle CRUD-Operationen:
# GET, POST, PUT, PATCH, DELETE
Jetzt wird's praktisch!
Was Django & DRF sind
Django Setup & Grundlagen
DRF Installation & erste API
Advanced Features
GET /api/movies/ → Liste aller Filme
POST /api/movies/ → Neuen Film erstellen
GET /api/movies/1/ → Film Details
PUT /api/movies/1/ → Film bearbeiten
DELETE /api/movies/1/ → Film löschen
GET /api/movies/1/actors/ → Schauspieler des Films
GET /api/artists/ → Alle Künstler
GET /api/castings/ → Alle Besetzungen
# Features:
✅ CRUD-Operationen
✅ Nested Relations (Film → Schauspieler)
✅ Authentication (Token/JWT)
✅ Permissions (Nur Admins dürfen löschen)
✅ Pagination (20 Filme pro Seite)
✅ Filtering (?genre=Sci-Fi)
✅ Search (?search=Matrix)
✅ API Documentation (Swagger)
✅ Unit Tests
✅ Production-ready!
→ Diese API können Sie für echte Projekte nutzen!
Django-Skills sind gefragt
"Django Developer" auf LinkedIn → 50,000+ Jobs
Bauen Sie Apps in Rekordzeit
Entwickler sind bis zu 10x produktiver mit Django!
Ein Framework, viele Möglichkeiten
Vom Hobby-Projekt bis Instagram - alles möglich!
Was Sie lernen, bleibt relevant
Skills die 2025 relevant sind, werden 2030 noch relevant sein!
┌──────────────────────────────────────────────────────────┐
│ │
│ Django (Core) Django REST Framework (DRF) │
│ ────────────── ──────────────────────────── │
│ │
│ 🌐 Websites 🔌 APIs │
│ 📄 HTML Output 📊 JSON Output │
│ 🎨 Templates 🔄 Serializers │
│ 👁️ Browser-Views 🎯 ViewSets │
│ 🖱️ Page Reloads ⚡ Smooth (SPA) │
│ │
│ ✅ Perfekt für: ✅ Perfekt für: │
│ - Blogs - Mobile Apps │
│ - CMS - React/Vue Apps │
│ - E-Commerce - Microservices │
│ - Admin-Panels - IoT-Backends │
│ │
│ 💡 Können kombiniert werden in einem Projekt! │
│ │
└──────────────────────────────────────────────────────────┘
Im nächsten Modul installieren wir Django und bauen unsere erste App!
Nächste Slide: Django Setup - Von der Installation zur ersten App
# models.py
from django.db import models
class Movie(models.Model):
title = models.CharField(max_length=200)
year = models.IntegerField()
rating = models.DecimalField(
max_digits=3,
decimal_places=1
)
def __str__(self):
return f"{self.title} ({self.year})"
# Befehle:
python manage.py makemigrations # Migration erstellen
python manage.py migrate # DB updaten
# Queries:
Movie.objects.all() # Alle Filme
Movie.objects.get(id=1) # Film mit ID 1
Movie.objects.filter(year=1999) # Filme von 1999
Movie.objects.create(...) # Neuen Film erstellen
<!-- templates/movies/list.html -->
{% extends 'base.html' %}
{% block content %}
<h1>Alle Filme</h1>
{% for movie in movies %}
<div>
<h2>{{ movie.title }}</h2>
<p>Jahr: {{ movie.year }}</p>
<p>Rating: {{ movie.rating }}</p>
</div>
{% empty %}
<p>Keine Filme vorhanden.</p>
{% endfor %}
{% if user.is_authenticated %}
<a href="{% url 'movie_create' %}">Neuer Film</a>
{% endif %}
{% endblock %}
<!-- Template Tags: -->
{{ variable }} <!-- Variable ausgeben -->
{% tag %} <!-- Template Tag -->
{% url 'name' %} <!-- URL generieren -->
{% static 'file.css' %} <!-- Static File -->
# views.py
from django.shortcuts import render, get_object_or_404
from .models import Movie
# Function-Based View
def movie_list(request):
movies = Movie.objects.all()
return render(request, 'movies/list.html', {
'movies': movies
})
def movie_detail(request, pk):
movie = get_object_or_404(Movie, pk=pk)
return render(request, 'movies/detail.html', {
'movie': movie
})
# Class-Based View
from django.views.generic import ListView
class MovieListView(ListView):
model = Movie
template_name = 'movies/list.html'
context_object_name = 'movies'
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.movie_list, name='movie_list'),
path('<int:pk>/', views.movie_detail, name='movie_detail'),
path('create/', views.movie_create, name='movie_create'),
]
# Projekt urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('movies/', include('movies.urls')),
]
# URLs aufrufen:
# /movies/ → movie_list
# /movies/1/ → movie_detail
# /movies/create/ → movie_create
# admin.py
from django.contrib import admin
from .models import Movie
@admin.register(Movie)
class MovieAdmin(admin.ModelAdmin):
list_display = ['title', 'year', 'rating']
list_filter = ['year', 'genre']
search_fields = ['title']
ordering = ['-year']
# Oder einfach:
admin.site.register(Movie)
# Superuser erstellen:
python manage.py createsuperuser
# Admin-Panel aufrufen:
# http://localhost:8000/admin/
# forms.py
from django import forms
from .models import Movie
class MovieForm(forms.ModelForm):
class Meta:
model = Movie
fields = ['title', 'year', 'rating']
# views.py
def movie_create(request):
if request.method == 'POST':
form = MovieForm(request.POST)
if form.is_valid():
form.save()
return redirect('movie_list')
else:
form = MovieForm()
return render(request, 'movies/create.html', {
'form': form
})
# Template:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Speichern</button>
</form>
# serializers.py
from rest_framework import serializers
from .models import Movie
# ModelSerializer (einfachste)
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = '__all__' # Alle Felder
# fields = ['id', 'title', 'year'] # Spezifische
# exclude = ['created_at'] # Außer
# Mit Custom Fields
class MovieSerializer(serializers.ModelSerializer):
actors_count = serializers.SerializerMethodField()
class Meta:
model = Movie
fields = ['id', 'title', 'actors_count']
def get_actors_count(self, obj):
return obj.castings.count()
# Nested Serializer
class MovieDetailSerializer(serializers.ModelSerializer):
actors = ArtistSerializer(many=True, read_only=True)
class Meta:
model = Movie
fields = '__all__'
# views.py
from rest_framework import viewsets
from .models import Movie
from .serializers import MovieSerializer
# ModelViewSet (alle CRUD-Operationen)
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
# ReadOnlyModelViewSet (nur lesen)
class MovieViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
# Custom Actions
from rest_framework.decorators import action
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
@action(detail=False, methods=['get'])
def top_rated(self, request):
movies = self.queryset.filter(rating__gte=8.0)
serializer = self.get_serializer(movies, many=True)
return Response(serializer.data)
# urls.py
from rest_framework.routers import DefaultRouter
from .views import MovieViewSet
router = DefaultRouter()
router.register('movies', MovieViewSet, basename='movie')
urlpatterns = router.urls
# Generiert automatisch:
# GET /movies/ → list
# POST /movies/ → create
# GET /movies/{id}/ → retrieve
# PUT /movies/{id}/ → update
# PATCH /movies/{id}/ → partial_update
# DELETE /movies/{id}/ → destroy
# Mit Custom Actions:
# GET /movies/top_rated/ → top_rated()
# Projekt urls.py
urlpatterns = [
path('api/', include('movies.urls')),
]
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
}
INSTALLED_APPS = [
'rest_framework.authtoken',
]
# Token erstellen:
from rest_framework.authtoken.models import Token
token = Token.objects.create(user=user)
# In Views nutzen:
class MovieViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]
# API-Request mit Token:
GET /api/movies/
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
# Built-in Permissions
from rest_framework.permissions import (
AllowAny,
IsAuthenticated,
IsAdminUser,
IsAuthenticatedOrReadOnly
)
class MovieViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticatedOrReadOnly]
# GET: Jeder
# POST/PUT/DELETE: Nur angemeldet
# Custom Permission
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.owner == request.user
class MovieViewSet(viewsets.ModelViewSet):
permission_classes = [IsOwnerOrReadOnly]
# settings.py - Pagination
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS':
'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20
}
# Filtering
pip install django-filter
INSTALLED_APPS = ['django_filters']
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
]
}
# In ViewSet:
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
filterset_fields = ['genre', 'year']
search_fields = ['title']
ordering_fields = ['year', 'rating']
# Nutzen:
# /api/movies/?genre=Sci-Fi
# /api/movies/?search=matrix
# /api/movies/?ordering=-year
# Virtuelle Umgebung erstellen
python -m venv venv
# Aktivieren (Windows)
venv\Scripts\activate
# Aktivieren (Linux/Mac)
source venv/bin/activate
# Django installieren
pip install django djangorestframework
# Projekt erstellen
django-admin startproject myproject
# App erstellen
python manage.py startapp myapp
# Development Server starten
python manage.py runserver
# Server auf anderem Port
python manage.py runserver 8080
# Migrations erstellen (nach Model-Änderungen)
python manage.py makemigrations
# Migrations anwenden
python manage.py migrate
# Migrations rückgängig (z.B. zu Migration 0003)
python manage.py migrate myapp 0003
# Alle Migrations anzeigen
python manage.py showmigrations
# SQL-Code einer Migration anzeigen
python manage.py sqlmigrate myapp 0001
# Datenbank zurücksetzen (VORSICHT!)
python manage.py flush
# Superuser erstellen
python manage.py createsuperuser
# Passwort ändern
python manage.py changepassword username
# Shell öffnen (Python mit Django-Kontext)
python manage.py shell
# Django Shell Plus (mit ipython)
pip install django-extensions ipython
python manage.py shell_plus
# Tests ausführen
python manage.py test
# Nur eine App testen
python manage.py test myapp
# Mit Coverage
pip install coverage
coverage run --source='.' manage.py test
coverage report
# Static Files sammeln (für Production)
python manage.py collectstatic
# Datenbank-Backup erstellen
python manage.py dumpdata > backup.json
# Datenbank-Backup laden
python manage.py loaddata backup.json
# System-Check (Konfiguration prüfen)
python manage.py check
# Deployment-Check
python manage.py check --deploy
# Dependencies auflisten
pip freeze > requirements.txt
# Dependencies installieren
pip install -r requirements.txt
So entwickeln Sie systematisch
Was soll die App können?
Beispiel: Movie-App
Models: Movie, Artist, MovieCasting
Relations: Movie ↔ Artist (ManyToMany via MovieCasting)
Endpoints: /movies/, /artists/, /castings/
Projekt aufsetzen
# Virtuelle Umgebung
python -m venv venv
venv\Scripts\activate
# Packages installieren
pip install django djangorestframework
# Projekt erstellen
django-admin startproject firstmovieapi
cd firstmovieapi
# App erstellen
python manage.py startapp movies
# In settings.py registrieren:
INSTALLED_APPS = [
'rest_framework',
'movies',
]
Datenstruktur definieren
# movies/models.py
class Movie(models.Model):
title = models.CharField(max_length=200)
year = models.IntegerField()
# ...
class Artist(models.Model):
first_name = models.CharField(max_length=100)
# ...
class MovieCasting(models.Model):
movie = models.ForeignKey(Movie, on_delete=CASCADE)
artist = models.ForeignKey(Artist, on_delete=CASCADE)
# ...
# Migrations
python manage.py makemigrations
python manage.py migrate
Testdaten einfach verwalten
# movies/admin.py
from django.contrib import admin
from .models import Movie, Artist, MovieCasting
admin.site.register(Movie)
admin.site.register(Artist)
admin.site.register(MovieCasting)
# Superuser erstellen
python manage.py createsuperuser
# Testdaten im Admin anlegen
# http://localhost:8000/admin/
Python ↔ JSON Konvertierung
# movies/serializers.py
from rest_framework import serializers
from .models import Movie, Artist
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = '__all__'
class ArtistSerializer(serializers.ModelSerializer):
class Meta:
model = Artist
fields = '__all__'
API-Logik implementieren
# movies/views.py
from rest_framework import viewsets
from .models import Movie, Artist
from .serializers import MovieSerializer, ArtistSerializer
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
class ArtistViewSet(viewsets.ModelViewSet):
queryset = Artist.objects.all()
serializer_class = ArtistSerializer
Routing einrichten
# movies/urls.py
from rest_framework.routers import DefaultRouter
from .views import MovieViewSet, ArtistViewSet
router = DefaultRouter()
router.register('movies', MovieViewSet)
router.register('artists', ArtistViewSet)
urlpatterns = router.urls
# firstmovieapi/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('movies.urls')),
]
API validieren
# Server starten
python manage.py runserver
# Im Browser testen:
http://localhost:8000/api/movies/
http://localhost:8000/api/artists/
# Mit Postman/curl testen
# GET, POST, PUT, DELETE probieren
# Unit Tests schreiben
# movies/tests.py
Features hinzufügen
Live gehen
Die beste Dokumentation im Web-Framework-Bereich!
Ein Framework für Websites UND APIs. Von Blogs bis Instagram - alles möglich.
DRF ist KEIN separates Framework, sondern macht Django zur API-Maschine. Nutzt Django's Models, Auth, etc.
Admin-Panel, User-Management, Sicherheit - alles dabei. Sie fokussieren auf Features, nicht Infrastruktur.
Model (Daten), Template (Darstellung), View (Logik). Klare Trennung = wartbarer Code.
Instagram, Spotify & 1000e andere nutzen Django. Skaliert von 10 bis Millionen User.
20 Jahre alt, riesige Community, beste Dokumentation. Hilfe ist immer verfügbar.
"Perfectionists with Deadlines" - MVP in Tagen möglich. Schnell produktiv sein.
Website + API in einem Projekt. Oder nur eins davon. Flexibel an Bedürfnisse anpassbar.
"The best time to plant a tree was 20 years ago. The second best time is now."
— Chinesisches Sprichwort
Nächstes Modul: Django Projekt Setup
Los geht's! 💪